前回のチュートリアルではPlanについてご紹介しました。今回はProtocolという概念についてです。Protocolは複数のPlanを組み合わせ、リモートワーカーの環境下にデプロイすることができます。デプロイ後は一回のコミュニケーションで実行することができます。
Protocolは複雑な演算処理を複数のワーカーに分散させることができる外観的なオブジェクトです。Protocolの重要な特徴は、ワーカー間で送られたり、検索されたりして、最終的に特定のワーカーにデプロイできる事です。そのため、ユーザーはProtocolをデザインすることで、ワーカーはそれをダウンロード、適用して、プログラムを実行する、なんて事が実現できるのです。
では、見てみましょう。
Authors:
Protocolはworker
とplan
の組みによって作成されます。worker
は実際のワーカーでもワーカーIDでも構いません。plan
はオブジェクトでもポインタでも構いません。
In [ ]:
import torch as th
import syft as sy
hook = sy.TorchHook(th)
# IMPORTANT: ローカルワーカーはクライアントワーカーにはなれません
hook.local_worker.is_client_worker = False
Planを3つ定義して、Protocolとして纏めてみましょう。機能は全て1を足すオペレーションです。
In [ ]:
@sy.func2plan(args_shape=[(1,)])
def inc1(x):
return x + 1
@sy.func2plan(args_shape=[(1,)])
def inc2(x):
return x + 1
@sy.func2plan(args_shape=[(1,)])
def inc3(x):
return x + 1
protocol = sy.Protocol([("worker1", inc1), ("worker2", inc2), ("worker3", inc3)])
次にProtocolをワーカーにくっつける必要があります。これは.deploy(*workers)
コマンドで実行できます。では、ワーカーを作成しましょう。
In [ ]:
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
charlie = sy.VirtualWorker(hook, id="charlie")
In [ ]:
workers = alice, bob, charlie
protocol.deploy(*workers)
各Planはそれぞれ関連づけられたワーカーの元に既に送られています。既にデプロイされているんです。
実は2つのフェーズから成り立っています。第一フェーズはワーカーとPlanの関連付けです。この段階ではワーカーの名前の文字列と関連づけられているだけです。第二フェーズでは、実際に各Planが各ワーカーの元へ送信されます。
In [ ]:
x = th.tensor([1.0])
ptr = protocol.run(x)
ptr
In [ ]:
ptr.get()
入力された1.0は3つのPlanを通過して3度1がたされ、4になって戻ってきています。
実は、引数にポインタを使ってPlanをリモート実行することも可能です。
In [ ]:
james = sy.VirtualWorker(hook, id="james")
In [ ]:
protocol.send(james)
In [ ]:
x = th.tensor([1.0]).send(james)
ptr = protocol.run(x)
ptr
見ての通り、結果として返されるポインタはJamesがもっていますね。
In [ ]:
ptr = ptr.get()
ptr
In [ ]:
ptr = ptr.get()
ptr
それではまだデプロイされていないProtocolを初期化して、リモートワーカーへ送ってみましょう。
In [ ]:
protocol = sy.Protocol([("worker1", inc1), ("worker2", inc2), ("worker3", inc3)])
protocol.tag('my_protocol')
protocol.send(james)
In [ ]:
me = sy.hook.local_worker # ローカルワーカーをmeとして取得しておきます
ここでProtocolを検索してみましょう。
In [ ]:
responses = me.request_search(['my_protocol'], location=james)
responses
今、Protocolのポインタに対してアクセスできます。
In [ ]:
ptr_protocol = responses[0]
他のポインタと同じように、実態を受け取る事も出来ます。
In [ ]:
protocol_back = ptr_protocol.get()
protocol_back
後は先ほど学んだ手順と同様です。
In [ ]:
protocol_back.deploy(alice, bob, charlie)
x = th.tensor([1.0])
ptr = protocol_back.run(x)
ptr.get()
Protocol関連のより実践的な例はこれから追加される予定ですが、Protocolが持つ可能性については十分に感じて頂けたと思います。
一番簡単に貢献できる方法はこのGitHubのレポジトリにスターを付けていただくことです。スターが増えると露出が増え、より多くのデベロッパーにこのクールな技術の事を知って貰えます。
最新の開発状況のトラッキングする一番良い方法はSlackに入ることです。 下記フォームから入る事ができます。 http://slack.openmined.org
コミュニティに貢献する一番良い方法はソースコードのコントリビューターになることです。PySyftのGitHubへアクセスしてIssueのページを開き、"Projects"で検索してみてください。参加し得るプロジェクトの状況を把握することができます。また、"good first issue"とマークされているIssueを探す事でミニプロジェクトを探すこともできます。
もし、ソースコードで貢献できるほどの時間は取れないけど、是非何かサポートしたいという場合は、寄付をしていただくことも可能です。寄附金の全ては、ハッカソンやミートアップの開催といった、コミュニティ運営経費として利用されます。
In [ ]: